package com.lime49.lockcrypt;

import com.lime49.lockcrypt.ui.AbstractDialog;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.ResourceBundle;
import javax.swing.border.EtchedBorder;
import javax.swing.filechooser.FileNameExtensionFilter;

/**
 * A form for importing or exporting accounts and account types.
 */
public class FrmImportExport extends AbstractDialog implements ILanguageParent {
    public enum DataType {
        XML,
        HTML,
        CSV,
        TXT,
        LockCrypt,
        LockCryptCompatibility,
        EncryptedXML
    }
    public enum DataDirection {
        Import,
        Export
    }

    private DataType type;
    private DataDirection direction;
    private FrmMainWindow parent;
    private JTextField txtFilename;
    private JFileChooser fc;
    private JCheckBox chkAccounts,
                      chkTypes;
    private JRadioButton radAllAccounts,
                         radSelectedAccounts;

    private LinkedHashMap<Account, Boolean> accounts = new LinkedHashMap<Account, Boolean>();
    //private ArrayList<Account> accounts;
    private ArrayList<AccType> types;

    public FrmImportExport(FrmMainWindow parent, DataType type, DataDirection direction, ArrayList<Account> accounts, ArrayList<AccType> types) {
        super((JFrame)parent, direction == DataDirection.Import ? parent.getLanguage().getString("IMPORT") : parent.getLanguage().getString("EXPORT"), true);
        this.parent = parent;
        this.type = type;
        this.direction = direction;
        this.types = types;
        ArrayList<Account> sorted = new ArrayList<Account>(accounts);
        Collections.sort(sorted, new Comparator<Account>() {
            public int compare(Account acc1, Account acc2) {
                return acc1.getName().compareTo(acc2.getName());
            }
        });
        for(Account acc : accounts) {
            if(!acc.getIsDeleted()) {
                this.accounts.put(acc, true);
            }
        }

        KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
        Action escapeAction = new AbstractAction() {
            // close the frame when the user presses escape
            public void actionPerformed(ActionEvent e) {
                thisDialog.dispose();
            }
        };
        this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
        this.getRootPane().getActionMap().put("ESCAPE", escapeAction);

        JPanel content = new JPanel(new GridBagLayout());
            content.setBorder(BorderFactory.createEmptyBorder(3,3,0,3));
            this.setContentPane(content);
        GridBagConstraints c = new GridBagConstraints();
            c.insets = Constants.GLOBALINSETS;
            c.weightx = 1;
            int curY = -1;
        JPanel pnlLocation = new JPanel(new GridBagLayout());
            pnlLocation.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), parent.getLanguage().getString("LOCATION")));
        JLabel lblLocation = new JLabel(parent.getLanguage().getString("DBFILE"));
            lblLocation.setDisplayedMnemonic('F');
            Utils.setgrid(c,++curY,0,2,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
            pnlLocation.add(lblLocation,c);
        txtFilename = new JTextField(20);
            Utils.setgrid(c,++curY,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,0.8);
            pnlLocation.add(txtFilename,c);
        JButton btnBrowse = new JButton(parent.getLanguage().getString("BROWSE"));
            btnBrowse.addActionListener(new BrowseListener());
            Utils.setgrid(c,curY,1,1,1,GridBagConstraints.NONE,GridBagConstraints.FIRST_LINE_START,0.2);
            pnlLocation.add(btnBrowse,c);
        fc = new JFileChooser();//parent.getPreferences().get("setLastDBLocation", System.getenv("USERPROFILE")));
            String lastLocation = parent.getPreferences().get("setLastExportLocation", System.getenv("USERPROFILE"));
            FileNameExtensionFilter extCSV = new FileNameExtensionFilter(parent.getLanguage().getString("CSVFILES"), "csv");
            FileNameExtensionFilter extEncXML = new FileNameExtensionFilter(parent.getLanguage().getString("ENCRYPTEDXMLFILTER"), "lxe");
            FileNameExtensionFilter extHTML = new FileNameExtensionFilter(parent.getLanguage().getString("HTMLFILES"), "html");
            FileNameExtensionFilter extLCDBs = new FileNameExtensionFilter(parent.getLanguage().getString("LOCKCRYPTDATABASES"), "lce");
            FileNameExtensionFilter extTxt = new FileNameExtensionFilter(parent.getLanguage().getString("TEXTFILES"), "txt");
            FileNameExtensionFilter extXML = new FileNameExtensionFilter(parent.getLanguage().getString("XMLFILES"), "xml");
            if(direction == DataDirection.Export) {
                    fc.addChoosableFileFilter(extCSV);
                    fc.addChoosableFileFilter(extEncXML);
                    fc.addChoosableFileFilter(extHTML);
                    fc.addChoosableFileFilter(extLCDBs);
                    fc.addChoosableFileFilter(extTxt);
                    fc.addChoosableFileFilter(extXML);
                fc.setDialogTitle(parent.getLanguage().getString("EXPORT")+"...");
                switch(type) {
                     case CSV:
                         fc.setSelectedFile(new File("LockCrypt.csv"));
                         fc.setFileFilter(extCSV);
                         txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.csv");
                         break;
                      case EncryptedXML:
                         fc.setSelectedFile(new File("LockCrypt.lxe"));
                         fc.setFileFilter(extEncXML);
                         txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.lxe");
                         break;
                      case HTML:
                         fc.setSelectedFile(new File("LockCrypt.html"));
                         fc.setFileFilter(extHTML);
                         txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.html");
                         break;
                     case LockCrypt:
                     case LockCryptCompatibility:
                         fc.setSelectedFile(new File("LockCrypt.lce"));
                         fc.setFileFilter(extLCDBs);
                         txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.lce");
                         break;
                     case TXT:
                         fc.setSelectedFile(new File("LockCrypt.txt"));
                         fc.setFileFilter(extTxt);
                         txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.txt");
                         break;
                     case XML:
                         fc.setSelectedFile(new File("LockCrypt.xml"));
                         fc.setFileFilter(extXML);
                         txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.xml");
                         break;
                }
            } else {
                    fc.addChoosableFileFilter(extEncXML);
                    fc.addChoosableFileFilter(extLCDBs);
                    fc.addChoosableFileFilter(extXML);
                    fc.setDialogTitle(parent.getLanguage().getString("IMPORT")+"...");
                    switch(type) {
                        case EncryptedXML:
                            fc.setSelectedFile(new File("LockCrypt.lxe"));
                            fc.setFileFilter(extEncXML);
                            txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.lxe");
                            break;
                        case LockCrypt:
                        case LockCryptCompatibility:
                            fc.setSelectedFile(new File("LockCrypt.lce"));
                            fc.setFileFilter(extLCDBs);
                            txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.lce");
                            break;
                        case XML:
                            fc.setSelectedFile(new File("LockCrypt.xml"));
                            fc.setFileFilter(extXML);
                            txtFilename.setText(lastLocation+File.separatorChar+"LockCrypt.xml");
                            break;
                    }
            }
        Box boxInclude = Box.createVerticalBox();
            boxInclude.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), parent.getLanguage().getString("INCLUDE")));
        chkAccounts = new JCheckBox(parent.getLanguage().getString("ACCOUNTS"));
            chkAccounts.setSelected(true);
            chkAccounts.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    radAllAccounts.setEnabled(chkAccounts.isSelected());
                    radSelectedAccounts.setEnabled(chkAccounts.isSelected());
                }
            });
            boxInclude.add(chkAccounts);
            Box boxAccounts = Box.createVerticalBox();
                boxAccounts.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
                ButtonGroup grpAccounts = new ButtonGroup();
                radAllAccounts = new JRadioButton(parent.getLanguage().getString("ALLACCOUNTS"));
                    radAllAccounts.setSelected(true);
                    boxAccounts.add(radAllAccounts);
                    grpAccounts.add(radAllAccounts);
                radSelectedAccounts = new JRadioButton(parent.getLanguage().getString("SELECTEDACCOUNTS"));
                    boxAccounts.add(radSelectedAccounts);
                    grpAccounts.add(radSelectedAccounts);
                JButton btnChooseAccounts = new JButton(parent.getLanguage().getString("CHOOSEACCOUNTS")+" "+(char)187);
                    btnChooseAccounts.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                            FrmChooseAccounts frmChooseAccounts = new FrmChooseAccounts((FrmImportExport)thisDialog, ((FrmImportExport)thisDialog).accounts);
                            radSelectedAccounts.setSelected(true);
                            ((FrmImportExport)thisDialog).accounts = frmChooseAccounts.getAccounts();
                        }
                    });
                    boxAccounts.add(btnChooseAccounts);
                if(direction == DataDirection.Export) {
                    boxInclude.add(boxAccounts);
                }
        chkTypes = new JCheckBox(parent.getLanguage().getString("ACCOUNTTYPES"));
            boxInclude.add(chkTypes);
        JPanel buttonBox = new JPanel(new FlowLayout(FlowLayout.TRAILING));
        JButton btnOk = new JButton(parent.getLanguage().getString("OK"));
            btnOk.setActionCommand("saveoptions");
            btnOk.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                   if(doImportExport()) {
                       dispose();
                   }
               }
            });
            buttonBox.add(btnOk);
        JButton btnCancel = new JButton(parent.getLanguage().getString("CANCEL"));
            btnCancel.setActionCommand("cancel");
            btnCancel.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                   dispose();
               }
            });
            buttonBox.add(btnCancel);
            btnOk.setMinimumSize(Constants.MINSIZE);
            btnOk.setPreferredSize(Constants.PREFSIZE);
            btnOk.setMaximumSize(Constants.MAXSIZE);
            btnCancel.setMinimumSize(Constants.MINSIZE);
            btnCancel.setPreferredSize(Constants.PREFSIZE);
            btnCancel.setMaximumSize(Constants.MAXSIZE);

            curY = -1;
            Utils.setgrid(c,++curY,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
            content.add(pnlLocation, c);
            Utils.setgrid(c,++curY,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
            content.add(boxInclude, c);
            Utils.setgrid(c,++curY,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
            content.add(buttonBox, c);
            c.weighty = 1;
            Utils.setgrid(c,++curY,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.FIRST_LINE_START,1);
            content.add(Box.createVerticalGlue(),c);
            this.pack();
            this.setLocationRelativeTo(parent);
            this.setVisible(true);

    }

    /**
     * Performs the import/export operation
     * @return True on success, otherwise false
     */
    private boolean doImportExport() {
        boolean success = false;
        File fileName = new File(txtFilename.getText());
        External exporter = new External(parent.getLanguage(), accounts, radAllAccounts.isSelected(), chkAccounts.isSelected(), types, chkTypes.isSelected());
        if(direction == DataDirection.Export) {
            try {
                if(fc.getFileFilter().accept(new File("1.csv"))) {
                    if(chkAccounts.isSelected() && chkTypes.isSelected()) {
                        JOptionPane.showMessageDialog(thisDialog, parent.getLanguage().getString("ERR_CSVONEOPTION"),parent.getLanguage().getString("ERROR"), JOptionPane.ERROR_MESSAGE);
                    } else {
                        exporter.exportToCSV(fileName);
                    }
                } else if(fc.getFileFilter().accept(new File("1.lce"))) {
                    if(type == DataType.LockCryptCompatibility) {
                        parent.saveDatabase(fileName.getCanonicalPath(), false, false);
                    } else {
                        parent.saveDatabase(fileName.getCanonicalPath(), false, true);
                    }
                } else if(fc.getFileFilter().accept(new File("1.xml"))) {
                    exporter.exportToXML(fileName, false);
                } else if(fc.getFileFilter().accept(new File("1.lxe"))) {
                    exporter.exportToXML(fileName, true);
                } else if(fc.getFileFilter().accept(new File("1.html"))) {
                    exporter.exportToHTML(fileName);
                } else { // assume text file
                    exporter.exportToTxt(fileName);
                }
                success = true;
            } catch(IOException ex) {
                JOptionPane.showMessageDialog(thisDialog, parent.getLanguage().getString("ERROR")+"#215: "+parent.getLanguage().getString("ERR_CANTSAVEFILE")+":\n"+ex.getLocalizedMessage(),parent.getLanguage().getString("ERROR"), JOptionPane.ERROR_MESSAGE);
            }
        } else {
            try {
                if(fc.getFileFilter().accept(new File("1.lce"))) {
                    if(type == DataType.LockCryptCompatibility) {
                        parent.loadDatabase(fileName.getCanonicalPath(), false);
                    } else {
                        parent.loadDatabase(fileName.getCanonicalPath(), true);
                    }
                } else if(fc.getFileFilter().accept(new File("1.xml"))) {
                    exporter.importFromXML(fileName, parent, false);
                } else if(fc.getFileFilter().accept(new File("1.lxe"))) {
                    exporter.importFromXML(fileName, parent, true);
                }
                success = true;
            } catch(Exception e) {
                JOptionPane.showMessageDialog(this, parent.getLanguage().getString("ERROR")+"#214: "+parent.getLanguage().getString("ERR_CANTOPENFILE")+":\n"+e.getLocalizedMessage(),parent.getLanguage().getString("ERROR"), JOptionPane.ERROR_MESSAGE);
            }
        }
        return success;
    }

     /*============================ ILanguageParent ==========================*/
    /**
     * Returns the current language ResourceBundle
     * @return The current language ResourceBundle
     */
    public ResourceBundle getLanguage() {
        return parent.getLanguage();
    }

    public Component getParentWindow() {
        return thisDialog;
    }

    public boolean getDebug() {
        return parent.getDebug();
    }
    /*============================ End ILanguageParent ==========================*/

    /**
     * Shows a dialog to allow the user to choose a filename when the browse button is clicked
     */
    class BrowseListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            boolean gotFile = false;
            File selectedFile = null;
            while(!gotFile) {
                int ret = 0;
                if(direction == DataDirection.Import) {
                    ret = fc.showOpenDialog(thisDialog);
                } else {
                    ret = fc.showSaveDialog(thisDialog);
                }
                if(ret == JFileChooser.APPROVE_OPTION) {
                    selectedFile = fc.getSelectedFile();
                    parent.getPreferences().put("setLastExportLocation",selectedFile.getParent());
                    if(direction == DataDirection.Export) {
                        if(selectedFile.exists()) {
                            if(JOptionPane.showConfirmDialog(thisDialog, parent.getLanguage().getString("ERR_FILEEXISTS_DESC"), parent.getLanguage().getString("ERR_FILEEXISTS"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
                                gotFile = true;
                            }
                        } else {
                            gotFile = true;
                        }
                    } else {
                        if(!selectedFile.exists()) {
                            JOptionPane.showMessageDialog(thisDialog, parent.getLanguage().getString("ERR_FILENOTFOUND_DESC"), parent.getLanguage().getString("ERR_FILENOTFOUND"), JOptionPane.WARNING_MESSAGE);
                        } else {
                            gotFile = true;
                        }
                    }
                } else if(ret == JFileChooser.CANCEL_OPTION) {
                    return;
                }
            }
            try {
                txtFilename.setText(fc.getSelectedFile().getCanonicalPath());
                parent.getPreferences().flush();
            } catch(Exception ex) {
                
            }
        }
    }
}
